package com.pupil.down.thread;

import com.pupil.down.system.SysSettings;
import com.pupil.down.util.FileUtil;
import com.pupil.down.util.HttpUtil;
import com.pupil.down.util.LogUtil;

import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.util.concurrent.Callable;

/**
 * @Description: 下载线程
 * @Author: pupil
 * @Date: 2024/09/28 下午 5:13
 */
public class DownloadThread implements Callable<Boolean> {

    /**
     * 每次读取的数据块大小
     */
    private static int BYTE_SIZE = 1024 * 100;
    /**
     * 下载链接
     */
    private String url;
    /**
     * 下载开始位置
     */
    private long startPos;
    /**
     * 要下载的文件区块大小
     */
    private Long endPos;
    /**
     * 标识多线程下载切分的第几部分
     */
    private Integer part;
    /**
     * 文件总大小
     */
    private Long contentLength;

    public DownloadThread(String url, long startPos, Long endPos, Integer part, Long contentLength) {
        this.url = url;
        this.startPos = startPos;
        this.endPos = endPos;
        this.part = part;
        this.contentLength = contentLength;
    }

    @Override
    public Boolean call() throws Exception {
        if (url == null || url.trim() == "") {
            throw new RuntimeException("下载路径不正确");
        }

        // 获取文件名
        String httpFileName = SysSettings.PATH + HttpUtil.getHttpFileName(url);
        if (part != null) {
            // 获取文件分片名
            httpFileName = httpFileName + SysSettings.FILE_TEMP_SUFFIX + part;
        }

        // 本地文件大小
        long localFileContentLength = FileUtil.getFileContentLength(httpFileName);
        LogThread.LOCAL_FINISH_SIZE.addAndGet(localFileContentLength);
        if (localFileContentLength >= endPos - startPos) {
            LogUtil.info("{} 已经下载完毕，无需重复下载", httpFileName);
            // 增加下载完成的线程数
            LogThread.DOWNLOAD_FINISH_THREAD.addAndGet(1);
            return true;
        }

        // 如果 endPos 等于 文件大小 则 endPos 设置为null，确保请求的范围有效
        // 因为服务器可能会返回额外的数据，如果endPos就与文件大小相同，会导致额外信息获取不了
        if (endPos.equals(contentLength)) {
            endPos = null;
        }


        HttpURLConnection httpUrlConnection = HttpUtil.getHttpUrlConnection(url, startPos + localFileContentLength, endPos);
        // 获取输入流
        try (InputStream input = httpUrlConnection.getInputStream();
             BufferedInputStream bis = new BufferedInputStream(input);
             RandomAccessFile oSavedFile = new RandomAccessFile(httpFileName, "rw")) {

            // 设置偏移位置，跳转到未获取的位置
            oSavedFile.seek(localFileContentLength);
            // 设置缓存
            byte[] buffer = new byte[BYTE_SIZE];
            // 缓存从字节流中获取到的字节长度
            int len = -1;
            // 读到文件末尾则返回-1
            while ((len = bis.read(buffer)) != -1) {
                // 将数据写入文件
                oSavedFile.write(buffer, 0, len);
                // 记录下载完成数据量
                LogThread.DOWNLOAD_SIZE.addAndGet(len);
            }

        } catch (FileNotFoundException e) {
            LogUtil.error("ERROR! 要下载的文件路径不存在 {} ", url);
        }catch (Exception e){
            LogUtil.error("下载出现异常，停止下载");
            e.printStackTrace();
            return false;
        }finally {
            httpUrlConnection.disconnect();
            LogThread.DOWNLOAD_FINISH_THREAD.addAndGet(1);
        }

        return true;
    }
}
